/*###################################################################*
#
# MP (Mitchell Pell) Base - CrossPlatform Base Utilities.
# Copyright (C) 2014  Mitchell Pell
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
####################################################################*/
#ifndef BASE_EVENT_H_
#define BASE_EVENT_H_

#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include "LockableMutex.h"
#include "Pause.h"
#include "ReceivesErrors.h"

using std::ostream;
using std::istream;
using std::string;

/*! @brief MP Base (General) Code */
namespace mp_base 
{ 
	/*! @brief General, inheritable, interface headers. */
	namespace interfaces 
	{

		typedef unsigned int uint;
		typedef unsigned long long ulong;
		/*!----------------------------------------------------------------
		*	@class		Event
		*	@brief		Template for an Event object.
		*
		*	@author		Mitchell Pell
		*	@date		11/05/2013
		*	@version	1.2.0
		*
		*	@revisions	Revision History:
		*
		*					- Version 1.2 11/05/2013
		*						-# Added the typedef shared_ptr<Event>
		*							!> Strongly recommended that this is 
		*								used instead of pointers.
		*						XX Added IOStream functionality
		*
		*					- Version 1.1 11/01/2013
		*						-# Added pre and post -- and ++ operators
		*						-# Added == and != operators
		*						-? Added target function handler for
		*							possible use.
		*
		*					- Version 1.0 09/27/2013
		*						-# Initial Make
		*
		-----------------------------------------------------------------*/
		class Event : public LockableMutex
		{
		public:
			typedef void(*HandlerFcn)(boost::shared_ptr<Event> evnt);

			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			  >>  Constructors and Destructor
			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

			/*! Default Constructor. */
			Event() : c_id(GetEventID())
				{ m_triggerCount = 0; 
				 m_targetFcn = NULL;}
			/*! Copy Constructor. */
			Event(const Event& evnt) : c_id(GetEventID())
				{m_triggerCount = evnt.m_triggerCount;
				 m_targetFcn = evnt.m_targetFcn;}
			/*! Destructor. */
			virtual ~Event(){}

			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			>>  Event Triggering
			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

			/*! Returns true on positive trigger count.  */
			virtual bool IsTriggered() const { return m_triggerCount > 0; }
			/*! Returns the actual trigger count. */
			uint TriggerCount() const { return m_triggerCount; }
			/*! PreIncrement trigger count. */
			Event& operator++(){ ++m_triggerCount;  return *this; }
			/*! PostIncrement trigger count. */
			Event  operator++(int){
				Event tmp(*this); operator++(); return tmp;}
			/*! PreDecrement trigger count. */
			Event& operator--(){ --m_triggerCount;   return *this; }
			/*! PostDecrement trigger count. */
			Event  operator--(int){
				Event tmp(*this); operator--(); return tmp;}

			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			>>  Event ID and Event Comparisons
			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

			/*! Gets the events ID */
			ulong GetID()const{ return c_id; }

			/*! Comparative operator compares the base ID */
			virtual bool operator==(const Event& evnt)
				{ return GetID() == evnt.GetEventID(); }
			/*! Comparative operator compares the base ID */
			virtual bool operator!=(const Event& evnt)
				{ return GetID() != evnt.GetEventID(); }

			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			>> Event Target Handler Function
			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

			/*! Gets the handler function. */
			HandlerFcn	GetHandlerFcn() const { return m_targetFcn; }
			/*! Sets the handler function. */
			void SetTargetHandlerFcn(HandlerFcn targetFcn)
				{ m_targetFcn = targetFcn; }

			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			>>  Event message
			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

			/*!  */
			virtual const string GetEventMessage() const 
				{ return std::to_string(c_id); }

			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			>>	Static Error Handler for Events
			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

			static void SetErrorHandler(ReceivesErrors* handler)
				{ s_errorHandler = handler;}

		private:

			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			>>  Static Event ID Generator
			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

			/*! Operation called by the constructor to get a
			 generated ID for this instance. */
			static ulong GetEventID(){
				while(!s_idMutex.try_lock()){Pause(1);}
				ulong tmp=s_idGenerator++;s_idMutex.unlock();return tmp;}

			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			>>  Members
			/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		protected:
			/*! Optional function handler that takes an Event. */
			HandlerFcn				m_targetFcn;
			/*! Number of times this event has beeen triggered. */
			volatile uint			m_triggerCount;
		public:
			/*! This instances ID */
			const    ulong			c_id;
		private:
			static	ReceivesErrors* s_errorHandler;
			/*! Static number used to generate instance IDs. */
			static   ulong			s_idGenerator;
			/*! Mutex used to lock the statis instance ID generator for
			access amongst multiple threads.*/
			static	 boost::mutex	s_idMutex;
		};

		typedef boost::shared_ptr<Event> spEvent;
	}
}

#endif